#include "server.h"


//返回值-1，操作失败；返回值0，操作成功；
static int jlogin(net_disk_t *ntd, char *password, char *user_name, char *token);
static int jregister(net_disk_t *ntd, char *password, char *user_name, char *token);
static int jcancel(net_disk_t *ntd, char *password, char *user_name);
//获得盐值
static void get_salt(char *salt);
//token加密
static void get_token(char *token, char *curr);

int login_register(net_disk_t *ntd){
    int cfd = accept(ntd->ser_fd, NULL, NULL);
    //登录还是注册
    //接收客户端发送的消息，判断是登录还是注册， 
    //1是登录， 2是注册, 3是注销, 4是token登录, 5、不想登录，退出
    int login_status;
    int ret = recv(cfd, &login_status, sizeof(login_status), MSG_WAITALL);
    ERROR_CHECK(ret, -1, "recv_login_status");
    if(ret == 0 || login_status == 5){
        //表示用户退出了，不想登录注册了
        return -1;
    }

    if(login_status == 4){
        char buf[512] = { 0 };
        recv(cfd, buf, sizeof(buf), MSG_WAITALL);
        int dtnum = decode_token(buf, buf);
        if(dtnum == -1){
            //token不对
            close(cfd);
            send(cfd, &dtnum, sizeof(int), MSG_NOSIGNAL);
            return -1;
        }
        user_t *ut = (user_t *)calloc(1, sizeof(user_t));
        ut->cli_fd = cfd;
        time_t curr_time = (time(NULL) - 1) % 30;
        ut->location_index = curr_time;

        send(cfd, &dtnum, sizeof(int), MSG_NOSIGNAL);
        return 99;
    }
    //登录/注册/注销
    //接收用户ID
    //接收用户密码
    char user_name[25] = { 0 };
    char password[11] = { 0 };
    ret = recv(cfd, &user_name, sizeof(user_name), MSG_WAITALL);
    ERROR_CHECK(ret, -1, "recv_user_id");

    ret = recv(cfd, password, sizeof(password), MSG_WAITALL);
    ERROR_CHECK(ret, -1, "recv_password");

    char token[512] = { 0 };
    //返回值-1，表示不存在 0表示登陆成功
    int return_num;
    if(login_status == 1){
        return_num = jlogin(ntd, password, user_name, token);
    }else if(login_status == 2){
        return_num = jregister(ntd, password, user_name, token);
    }else{
        return_num = jcancel(ntd, password, user_name);
        ret = send(cfd, &return_num, sizeof(int), MSG_NOSIGNAL);
        ERROR_CHECK(ret, -1, "send_return_num");
        return 0;
    }
    ret = send(cfd, &return_num, sizeof(int), MSG_NOSIGNAL);
    ERROR_CHECK(ret, -1, "send_return_num");


    if(return_num == 0){
        //登录注册成功
        user_t *ut = (user_t *)calloc(1, sizeof(user_t));
        ut->cli_fd = cfd;
        time_t curr_time = (time(NULL) - 1) % 30;
        ut->location_index = curr_time;


        send(cfd, token, sizeof(token), MSG_NOSIGNAL);
    }else{
        close(cfd);
    }

    return return_num;
}


static int jlogin(net_disk_t *ntd, char *password, char *user_name, char *token){

    char buf[1024] = { 0 };
    sprintf(buf, "select  pass_word, salt from user_info where user_name = '%s'", user_name);

    char curr[2][1024] = { { 0 } };
    int sql_num = mysql_select_get_one_row(ntd->mysql, buf, curr);

    if(sql_num != 1){
        return -1;
    }

    if(strcmp(crypt(password, curr[1]), curr[0]) == 0){
        //账号密码都正确，给用户生成token
        sprintf(buf, "select id from user_info where user_name = '%s'", user_name);
        char curr[5] = { 0 };
        sql_num = mysql_select_get_one_str(ntd->mysql, buf, curr);
        if(sql_num != 1){
            return -1;
        }
        get_token(token, curr);

        return 0;
    }
    return -1;
}


static int jregister(net_disk_t *ntd, char *password, char *user_name, char *token){
    char buf[1024] = { 0 };
    sprintf(buf, "select * from user_info where user_name = '%s'", user_name);
    int sql_num = mysql_select_file_is_exist(ntd->mysql, buf);
    if(sql_num != 0){
        return -1;
    }

    char salt[20] = { 0 };
    get_salt(salt);
    bzero(buf, sizeof(buf));
    sprintf(buf,"insert into user_info (user_name, pass_word, salt) values('%s', '%s', '%s')", user_name, crypt(password, salt), salt);
    //在数据库中加入用户
    if (mysql_query(ntd->mysql, buf)) {
        printf("%s\n", mysql_error(ntd->mysql));                                                                       
        return -1;
    }

    bzero(buf, sizeof(buf));
    sprintf(buf, "select id from user_info where user_name = '%s'", user_name);
    char curr[10] = { 0 };
    sql_num = mysql_select_get_one_str(ntd->mysql, buf, curr);
    if(sql_num != 1){
        return -1;
    }

    //为该用户创建根目录
    bzero(buf, sizeof(buf));
    sprintf(buf, "insert into file_info (user_id, file_name, father_id, file_path, file_type, hash_id)"
            "values('%s', '/', 0, '/', 1, 0)", curr);                         
    if (mysql_query(ntd->mysql, buf)) {
        printf("%s\n", mysql_error(ntd->mysql));
        return -1;
    }
    get_token(token, curr);
    return 0;
}


static void get_salt(char *salt){
    const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    size_t charset_size = sizeof(charset) - 1;

    srand(time(NULL));
    char buf[9] = { 0 };
    for(int i = 0; i < 8; i++){
        buf[i] = charset[rand()%charset_size];
    }
    sprintf(salt, "$6$%s$", buf);
}

static void get_token(char *token, char *user_id){
    // 用于存储生成的JWT字符串
    char* jwt; 
    // JWT字符串的长度
    size_t jwt_length;  

    // 初始化编码参数结构体
    struct l8w8jwt_encoding_params params;
    l8w8jwt_encoding_params_init(&params);

    // 设置JWT使用的算法，这里使用HS512
    params.alg = L8W8JWT_ALG_HS512;

    // 设置JWT的主要荷载部分内容:
    params.aud = user_id;
    params.exp = time(NULL) + 60;

    // 设置加密密钥
    params.secret_key = (unsigned char*)"snow string token key";
    params.secret_key_length = strlen((char *)params.secret_key);

    // 输出变量
    params.out = &jwt;
    params.out_length = &jwt_length;

    // 加密
    l8w8jwt_encode(&params);
    strcpy(token, jwt);

    // 释放token 字符串的内存
    l8w8jwt_free(jwt);
}
static int jcancel(net_disk_t *ntd, char *password, char *user_name){
    char buf[1024] = { 0 };
    sprintf(buf, "select  pass_word, salt from user_info where user_name = '%s'", user_name);

    char curr[2][1024] = { { 0 } };
    int sql_num = mysql_select_get_one_row(ntd->mysql, buf, curr);

    if(sql_num != 1){
        return -1;
    }

    if(strcmp(crypt(password, curr[1]), curr[0]) == 0){
        bzero(buf, sizeof(buf));
        sprintf(buf, "select id from user_info where user_name = '%s'", user_name);
        char curr[10] = { 0 };
        sql_num = mysql_select_get_one_str(ntd->mysql, buf, curr);
        if(sql_num != 1){
            return -1;
        }

        bzero(buf, sizeof(buf));
        sprintf(buf, "delete from user_info where id = %s", curr);                         
        if (mysql_query(ntd->mysql, buf)) {
            printf("%s\n", mysql_error(ntd->mysql));
            return -1;
        }
        bzero(buf, sizeof(buf));
        sprintf(buf, "delete from file_info where user_id = '%s'", curr);                         
        if (mysql_query(ntd->mysql, buf)) {
            printf("%s\n", mysql_error(ntd->mysql));
            return -1;
        }
        return 0;
    }
    return -1;
}
